package virtualadvisor;

import java.util.ArrayList;
import java.util.LinkedList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;


public class DegreeProgress {
	private final JPanel contentPanel = new JPanel();
	static private final int REQUIRED_CREDITS = 120;
	
	//used for GPA calculation
	static private final int A_WEIGHT = 4;
	static private final int B_WEIGHT = 3;
	static private final int C_WEIGHT = 2;
	static private final int D_WEIGHT = 1;
	static private final int F_WEIGHT = 0;
	
	private LinkedList<Plan> plans;
	private LinkedList<Course> currentReqs;
	private LinkedList<String> gepReqs;
	private LinkedList<Course> completedCourses;
	private LinkedList<String> completedGEPReqs;
	private int degreeCredits;
	private double degreeGPA;
	private double degreePoints;
	
	/**
	 * Name: DegreeProgress
	 * Precondition: None
	 * Postcondition: Creates a DegreeProgress object with the given starting
	 * 				  requirements 
	 * @param reqs - list of major requirements
	 * @param gepReq - list of general education requirements
	 */
	public DegreeProgress(LinkedList<Course> reqs, LinkedList<String> gepReq) {
		this.currentReqs = new LinkedList<Course>(reqs);
		this.gepReqs = gepReq;
		
		this.plans = new LinkedList<Plan>();
		this.completedCourses = new LinkedList<Course>();
		this.completedGEPReqs = new LinkedList<String>();
		
		this.degreeCredits = 0;
		this.degreeGPA = 0;
		this.degreePoints = 0;
	}
	
	/**
	 * Name: Constructor
	 * Precondition: None
	 * Postcondition: Creates a new DegreeProgress
	 * @param plan
	 * @param completedCourses
	 * @param completedGEP
	 * @param reqs
	 * @param gepReq
	 * @param degreeCredits
	 * @param degreeGPA
	 * @param degreePoints
	 */
	public DegreeProgress(LinkedList<Plan> plan, LinkedList<Course> completedCourses, 
			LinkedList<String> completedGEP, LinkedList<Course> reqs, LinkedList<String> gepReq, 
			int degreeCredits, double degreeGPA, double degreePoints){
		
		this.plans = new LinkedList<Plan>(plan);
		this.completedCourses = completedCourses;
		this.completedGEPReqs = completedGEP;
		
		this.currentReqs = new LinkedList<Course>(reqs);
		this.gepReqs = gepReq;
		
		this.degreeCredits = degreeCredits;
		this.degreeGPA = degreeGPA;
		this.degreePoints = degreePoints;
	}
	
	/**
	 * Name: createPlan
	 * Precondition: Plan with the given name cannot already exist
	 * Postcondition: Creates a new plan with the given name
	 * @param name
	 */
	public void createPlan(String name) { 
		String planName;
		for(int i = 0; i < plans.size(); i++) {
			planName = plans.get(i).getName();
			if(planName.equalsIgnoreCase(name)) {
				JOptionPane.showMessageDialog(contentPanel, 
						"The plan already exists!","Error", 
						JOptionPane.ERROR_MESSAGE);
				return;
			}
		}
		plans.add(new Plan(name)); 
	}
	
	/**
	 * Name: deletePlan
	 * Precondition: Plan needs to exist
	 * Postcondition: Completely deletes plan with the given name
	 * @param name
	 */
	public void deletePlan(String name) {
		String planName;
		for(int i = 0; i < plans.size(); i++) {
			planName = plans.get(i).getName();
			if(planName.equalsIgnoreCase(name)) {
				plans.remove(i);
				return;
			}
		}
		JOptionPane.showMessageDialog(contentPanel, 
				"The plan does not exist.","Error", 
				JOptionPane.ERROR_MESSAGE);
	}
	
	/**
	 * Name: addSemester
	 * Precondition: None
	 * Postcondition: adds the given semester to the given plan
	 * @param p
	 * @param s
	 */
	public void addSemester(Plan plan, Semester semester) {
		Plan addToPlan = findPlan(plan);
		addToPlan.addSemester(semester);
	}
	
	public void addPlan(Plan plan){
		plans.add(plan);
	}
	
	/**
	 * Name: deleteSemester
	 * Precondition: None
	 * Postcondition: deletes the chosen semester from the given plan
	 * @param p
	 * @param s
	 */
	public void deleteSemester(Plan p, Semester s) {
		Plan deleteFromPlan = findPlan(p);
		deleteFromPlan.deleteSemester(s);
	}
	
	/**
	 * Name: addCompleteCourse
	 * Precondition: None
	 * Postcondition: adds a course to the list of current completed courses
	 * 				  and removes from the requirements that are left
	 * @param c - course to be added
	 */
	public void addCompleteCourse(Course c) {
		completedCourses.add(c);
		
		// add GEP requirements if the course has any
		if(c.isGEP()) {
			LinkedList<String> cGEP = (LinkedList<String>)c.getGEPReq();
			
			for(int i = 0; i < cGEP.size(); i++) {
				completedGEPReqs.add(cGEP.get(i));
				gepReqs.remove(cGEP.get(i));
			}
		}
			
		/*System.out.println("Course name: " + c.getName());
		System.out.println("Req Course name: " + currentReqs.get(0).getName());*/
		
		//removes the course from the requirements yet to be completed
		currentReqs.remove(c);
		
		//accounts for possible honors courses left
		for(int j = 0; j < currentReqs.size(); j++)
			if(currentReqs.get(j).getName().contains(c.getName()) ||
				c.getName().contains(currentReqs.get(j).getName()))
				currentReqs.remove(j);
		
		degreeCredits += c.getCredits();
		
		calculateGPA();
	}
	
	/**
	 * Name: getRemainingCourses
	 * Precondition: None
	 * Postcondition: returns a list of courses yet to be completed for the
	 *                major program
	 */
	public LinkedList<Course> getRemainingCourses() { return currentReqs; }
	
	/**
	 * Name: majorCompleted
	 * Precondition:
	 * Postcondition: determines if a student has completed the major degree
	 * 				  program
	 */
	public boolean majorCompleted() {
		if(takenReqCourses() && (degreeCredits >= REQUIRED_CREDITS))
			return true;
		else
			return false;
	}
	
	/**
	 * Name: getCompletedCourses
	 * Precondition: None
	 * Postcondition: returns list of completed courses
	 */
	public LinkedList<Course> getCompletedCourses() { return completedCourses; }
	
	/**
	 * Name: getGPA
	 * Precondition: None
	 * Postcondition: returns the current GPA
	 */
	public Double getGPA() { return degreeGPA; }
	
	/**
	 * Name: calculateGPA
	 * Precondition: None
	 * Postcondition: uses the grades in the list of completed courses to determine
	 * 				  the current GPA and assigns degreeGPA as such
	 */
	private void calculateGPA() {
		char grade;
		Course c;
		degreePoints = 0;
		for(int i = 0; i < completedCourses.size(); i++) {
			c = completedCourses.get(i);
			grade = c.getGrade();
			
			// weights the credits based on the grade
			switch(grade){
			case 'A':
				degreePoints += A_WEIGHT * c.getCredits();
				break;
			case 'B':
				degreePoints += B_WEIGHT * c.getCredits();
				break;
			case 'C':
				degreePoints += C_WEIGHT * c.getCredits();
				break;
			case 'D':
				degreePoints += D_WEIGHT * c.getCredits();
				break;
			case 'F':
				degreePoints += F_WEIGHT * c.getCredits();
				break;
			default:
				break;
			}
		}
		
		degreeGPA = degreePoints / degreeCredits;
	}
	
	public ArrayList<Course> getCourseList(Plan p, String season, int year){
		Plan plan = findPlan(p); 
		Semester semester = plan.getSemester(season.trim(), year);

		return semester.getCourses();
	}
	
	public Plan getPlan(String p, String term) {
		for(int i = 0; i < plans.size(); i++)
			if(plans.get(i).getName().equals(p))
				return plans.get(i);
		
		return null;
	}
	
	/**
	 * Name: takenReqCourses
	 * Precondition: None
	 * Postcondition: determines if all required classes have been taken
	 */
	private boolean takenReqCourses() {
		if(currentReqs.size() == 0 && gepReqs.size() == 0)
			return true;
		else
			return false;
	}
	
	private Plan findPlan(Plan p) {
		for(int i = 0; i < plans.size(); i++)
			if(plans.get(i).equals(p))
				return plans.get(i);
		
		return null;
	}
	
    public String XMLCoder(){
    	String xml = "";
    	
    	xml = xml + " <completed>\n";
    	for(int y = 0; y < completedCourses.size(); y++)
    		xml = xml + completedCourses.get(y).XMLCoder();  // Completed Course info
    	xml = xml + "   </completed>\n";
    	
    	for(int x = 0; x < plans.size(); x++)
    		xml = xml + plans.get(x).XMLCoder();  // Planned Course info	
    	
    	if(completedGEPReqs.size() != 0 || completedGEPReqs == null){
    		xml = xml + "  <completedGEP>\n";
    		for(int y = 0; y < completedGEPReqs.size(); y ++)
    			xml = xml + "   <course>" + completedGEPReqs.get(y) + "</course>\n";
    		
    		xml = xml + "   </completedGEP>\n";
    	}
    	
       	xml = xml + "  <requirements>\n";
    	for(int y = 0; y < currentReqs.size(); y++)
    		xml = xml + currentReqs.get(y).XMLCoder();  // Requirements info
    	xml = xml + "   </requirements>\n";
    	
    	if(gepReqs.size() != 0 || gepReqs == null){
    		xml = xml + "  <geprequirements>\n";
    		for(int y = 0; y < gepReqs.size(); y ++)
    			xml = xml + "   <course>" + gepReqs.get(y) + "</course>\n";
    		
    		xml = xml + "   </geprequirements>\n";
    	}
    	
    	xml = xml + " <degreeCredits>" + degreeCredits +"</degreeCredits>\n";
		xml = xml + " <degreeGPA>" + degreeGPA +"</degreeGPA>\n";
		xml = xml + " <degreePoints>" + degreePoints +"</degreePoints>\n";
		
    	return xml;
    }
	
	public static void main(String[] args) {
		LinkedList<String> myGEP = new LinkedList<String>();
		//myPre.add("MATH150");
		
		Course c = new Course("CMSC201", "CMSC", 201, "COMPUTERS", "Computer Stuff", ' ', 4, myGEP, false, null);
		Course c1 = new Course("CMSC203", "CMSC", 203, "COMPUTERS", "Computer Stuff", 'A', 4, myGEP, false, null);
		Course c3 = new Course("CMSC203H", "CMSC", 203, "COMPUTERS", "Computer Stuff", 'A', 4, myGEP, false, null);
		LinkedList<Course> cs = new LinkedList<Course>();
		cs.add(c);
		cs.add(c3);
		
		//Course c2 = new Course("CMSC203", "CMSC", 203, "COMPUTERS", "Computer Stuff", 'A', 4, myGEP, false, null);
		
		//cs.add(c);
		cs.add(c1);
		

		DegreeProgress d = new DegreeProgress(cs, myGEP);
		
		/*(for(int i = 0; i < d.currentReqs.size(); i++)
			System.out.println("Current reqs are: " + d.currentReqs.get(i).getName());
		
		d.addCompleteCourse(new Course("CMSC203", "CMSC", 203, "COMPUTERS", "Computer Stuff", 'A', 4, myGEP, false, null));
		//d.addCompleteCourse(new Course("CMSC221", "CMSC", 221, "COMPUTERS", "Computer Stuff", 'C', 3, myPre, false, null));
		System.out.println(d.XMLCoder());
		
		if(d.majorCompleted())
			System.out.println("Complete");
		else
			System.out.println("Not Complete");
		
		System.out.println("Current reqs:" + d.currentReqs.size());
		
		for(int i = 0; i < d.currentReqs.size(); i++)
			System.out.println("Current reqs are: " + d.currentReqs.get(i).getName());*/
		
		String name = "CMSC_IS_BUSINESS";
		d.createPlan(name);
		System.out.println("First plan name is: " + d.plans.get(0));
		//d.createPlan(name);
		String name2 = "CMSC";
		d.createPlan(name2);
		//System.out.println("Second plan name is: " + d.plans.get(1));
		d.deletePlan(name);
		System.out.println("Number of plans: " + d.plans.size());
		//d.deletePlan(name);
		d.deletePlan(name2);
		System.out.println("Number of plans: " + d.plans.size());
		d.deletePlan(name);
	}
}
